package com.hilon.segment.mybatis.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hilon.segment.mybatis.service.impl.UserDetailServiceImpl;
import com.hilon.segment.mybatis.manager.MyFilterSecurityInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 添加 @EnableWebSecurity 以解决 "Could not autowire. No beans of 'HttpSecurity' type found." 问题。
 * 详见该注解的@Import()项。
 */
@EnableWebSecurity
@Configuration
public class SecurityConfig {

    @Resource
    private ObjectMapper objectMapper;

    private final MyFilterSecurityInterceptor securityInterceptor;

    public SecurityConfig(MyFilterSecurityInterceptor securityInterceptor) {
        this.securityInterceptor = securityInterceptor;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(securityInterceptor, FilterSecurityInterceptor.class)
                .userDetailsService(customUserDetailsService())
                .authorizeHttpRequests((authorize) -> authorize
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .permitAll()
                        .successHandler((request, response, authentication) -> {
                            System.out.println("认证成功!");
                            Map<String, Object> map = new HashMap<>();
                            map.put("code", 200);
                            map.put("msg", "登录成功");
                            map.put("resultData", authentication);
                            response.setContentType("application/json;charset=utf-8");
                            PrintWriter out = response.getWriter();
                            out.write(objectMapper.writeValueAsString(map));
                            out.flush();
                            out.close();
                        })
                        .failureHandler((request, response, exception) -> {
                            response.setContentType("application/json;charset=utf-8");
                            response.setStatus(401);
                            System.out.println("认证失败!");
                            Map<String, Object> map = new HashMap<>();
                            map.put("code", 401);
                            map.put("msg", "令牌、用户名、密码错误");
                            map.put("resultData", exception);
                            PrintWriter out = response.getWriter();
                            out.write(objectMapper.writeValueAsString(map));
                            out.flush();
                            out.close();
                        })
                )
                .logout().logoutSuccessHandler((request, response, authentication) -> {
                    System.out.println("认证成功!");
                    Map<String, Object> map = new HashMap<>();
                    map.put("code", 200);
                    map.put("msg", "退出成功");
                    map.put("resultData", authentication);
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    out.write(objectMapper.writeValueAsString(map));
                    out.flush();
                    out.close();
                }).deleteCookies("JSESSIONID") // 退出登录时, 将浏览器的cookie清除掉.
                .and()
                // 开启跨域
                .cors(AbstractHttpConfigurer::disable)
                // 跨站请求伪造，开启后，允许 API POST (如:  postman )工具测试。
                .csrf(AbstractHttpConfigurer::disable)
                .httpBasic()
                // 配置未登录时的返还提示。
                .authenticationEntryPoint((request, response, exception) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                    PrintWriter out = response.getWriter();
                    Map<String, Object> map = new HashMap<>();
                    map.put("code", 401);
                    map.put("msg", "未登录!");
                    out.write(objectMapper.writeValueAsString(map));
                    out.flush();
                    out.close();
                });
        return http.build();
    }

    @Bean
    UserDetailServiceImpl customUserDetailsService() {
        return new UserDetailServiceImpl();
    }

    @Bean
    static PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
